package bierki;

import gameManager.Position;

import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

/**
 * Bierka Król, różni się od innych nie tylko ruchami, ale także posiada funkcjonalność
 * umożliwiającą w każdej turze gry sprawdzić czy nie zaszedł nad nim szach lub mat
 * @author Konrad Sobczak
 *
 */
public class Krol extends Bierka {

	/**
	 * Konstruktor wywołujący jedynie konstruktor klasy bazowej, patrz Bierka
	 * @param obrazek
	 * @param kolor
	 * @param x
	 * @param y
	 */
	public Krol(String obrazek,BierkaKolor kolor, int x, int y) {
		super(obrazek,BierkaTyp.KROL,kolor,x, y);
	}
	
	public Krol(BierkaKolor kolor, int x, int y) {
		super(BierkaTyp.KROL,kolor,x, y);
	}

	/**
	 * Metoda przeciążana z Bierka.java, sprawdza prawidłowośc ruchu na pozycje końcową xk yk
	 */
	@Override
	public boolean sprawdzRuch(Bierka[][] szachownica, int xk, int yk) {

		if (pozaSzachownica(xk,yk)) return false;

		if (sprawdzBicie(szachownica[xk][yk])) return false;
		
		if (Math.abs(xk - x) > 1 ||  Math.abs(yk - y) > 1) return false;
		
		Krol krolTmp = new Krol(kolor,xk,yk);
		if (sprawdzSzach(szachownica,xk,yk,krolTmp)) return false;
		
		return true;
	}

	
	@Override
	public boolean sprawdzRuch(Bierka[][] szachownica, int xk, int yk, Krol krol) {

		if (pozaSzachownica(xk,yk)) return false;

		if (sprawdzBicie(szachownica[xk][yk])) return false;
		
		if (Math.abs(xk - x) > 1 ||  Math.abs(yk - y) > 1) return false;
		
		Krol krolTmp = new Krol(kolor,xk,yk);
		if (sprawdzSzach(szachownica,xk,yk,krolTmp)) return false;
		
		return true;
	}
	
	@Override
	public Vector<Point2D> validateMove(Bierka[][] plansza, int xp, int yp) {
		// TODO Auto-generated method stub
		return null;
	}
	
	/**
	 * Szach następuje jeśli conajmniej jedna z bierek ma bicie na pole króla
	 * @param szachownica - aktualny stan szachownicy, rozmieszczenie bierek, null - pusto
	 * @return - prawda jeśli szach, fałsz jeśli nie
	 */
	public boolean szach(Bierka[][] szachownica) {
		
		List<Position> szachujace = bierkiSzachujace(szachownica);	
		return szachujace.size() > 0;
		

	}
	/**
	 * SPrawdza czy nie nastąpił mat po ruchu przeciwnika, sprawdzenie na podstawie aktualnego stanu szachownicy i wlasnych bierek mogących bronić króla lub też zasłonić
	 * @param szachownica szachowica
	 * @param bierki Vektor wlasnych bierek;
	 * @return - prawda jeśli mat, fałsz jeśli nie
	 */
	public boolean mat(Bierka[][] szachownica, Vector<Bierka> bierki) {
		
		List<Position> szachujace = bierkiSzachujace(szachownica);	
		if (szachujace.size() == 0) return false;

		if (sprawdzRuch(szachownica,x-1,y-1,this)) return false;
		if (sprawdzRuch(szachownica,x-1,y,this)) return false;
		if (sprawdzRuch(szachownica,x-1,y+1,this)) return false;
		if (sprawdzRuch(szachownica,x+1,y-1,this)) return false;
		if (sprawdzRuch(szachownica,x+1,y,this)) return false;
		if (sprawdzRuch(szachownica,x+1,y+1,this)) return false;
		if (sprawdzRuch(szachownica,x,y+1,this)) return false;
		if (sprawdzRuch(szachownica,x,y-1,this)) return false;
	
		 
		//jesli wiecej niz jedna figura szach - mat		
		if (szachujace.size() > 1) return true;
		
		for (Position cc : szachujace) {
			Bierka szachujaca = szachownica[cc.getX()][cc.getY()];
			List<Position> zaslaniajace = new LinkedList<Position>();
			if (szachujaca.typ == BierkaTyp.KONIK) {
				zaslaniajace.add(new Position(szachujaca.getX(),szachujaca.getY()));
			} else {
				int dy = y - szachujaca.getY();
				int dx = x - szachujaca.getX();
				
				int krokY = (int)Math.signum(dy);
				int krokX = (int)Math.signum(dx);
				
				int ypos = szachujaca.getY();
				int xpos = szachujaca.getX();
				
				while (xpos != x || ypos != y) {
					
					zaslaniajace.add(new Position(xpos,ypos));
					
					ypos += krokY;
					xpos += krokX;
				}
			}
			
			for (Bierka bierka : bierki) {
				for (Position pos : zaslaniajace) {
					if (bierka.sprawdzRuch(szachownica,pos.getX(),pos.getY())) return false;
				}
			}
		}
		
		return true;
	}

	public List<Position> bierkiSzachujace(Bierka[][] szachownica) {
		
		List<Position> retval = new LinkedList<Position>();
		
		//konik
		for (int yi = -2; yi < 3; yi++ ) {
			if (yi == 0)  continue;
			int xp = 3 - Math.abs(yi);
			for (int p = 1; p < 3; p++) {
				//xi *= (-1)^p ;
				int xi = xp * (int)Math.pow(-1,p);
				if (!pozaSzachownica(x+xi,y+yi) && 
						szachownica[x+xi][y+yi] != null && 
						szachownica[x+xi][y+yi].getTyp() == BierkaTyp.KONIK && 
						szachownica[x+xi][y+yi].getKolor() != kolor) retval.add(new Position(x+xi,y+yi));
				
			}
		}
		
		//wieza / krolowa
		for (int p = 1; p < 3; p++) {
			int s = (int)Math.pow(-1,p);;
			for (int xk = x + s; xk >= 0 && xk <= 7 ; xk += s) {
				if (szachownica[xk][y] != null) { 
					if (( szachownica[xk][y].getTyp() == BierkaTyp.WIEZA  || 
					  szachownica[xk][y].getTyp() == BierkaTyp.KROLOWA	) && 
					  szachownica[xk][y].getKolor() != kolor) retval.add(new Position(xk,y));
					break;
				}
			}	
			
			for (int yk = y + s; yk >= 0 && yk <= 7 ; yk += s) {
				if (szachownica[x][yk] != null) { 
					if (( szachownica[x][yk].getTyp() == BierkaTyp.WIEZA  || 
					  szachownica[x][yk].getTyp() == BierkaTyp.KROLOWA	) && 
					  szachownica[x][yk].getKolor() != kolor) retval.add(new Position(x,yk));
					break;
				} 
			}	
		}
		
		//goniec / krolowa
		for (int p = 1; p < 5; p++) {
			int rx = (int)Math.pow(-1,p);
			int ry = (int)Math.pow(-1,Math.floor(p/3)); 
			for (int xi = x + rx, yi = y + ry; xi >= 0 && xi <= 7 && yi >= 0 && yi <= 7; xi += rx, yi += ry) {
				//if (szachownica[xi][yi] != null && szachownica[xi][yi].getKolor() == kolor) break;
				if (szachownica[xi][yi] != null) { 
					if (( szachownica[xi][yi].getTyp() == BierkaTyp.GONIEC  || 
						  szachownica[xi][yi].getTyp() == BierkaTyp.KROLOWA	) && 
						  szachownica[xi][yi].getKolor() != kolor) retval.add(new Position(xi,yi));
					break;
				}
			}
		}
		
		//pionek
		for (int p = 1; p < 3; p++) {
			int xi = x + (int)Math.pow(-1,p);
			int yi = y + ((kolor == BierkaKolor.CZARNY) ? 1 : -1);
			if (pozaSzachownica(xi,yi)) continue;
			
			if (szachownica[xi][yi] != null && 
					szachownica[xi][yi].getTyp() == BierkaTyp.PIONEK && 
					szachownica[xi][yi].getKolor() != kolor) retval.add(new Position(xi,yi));
		}
		
		
		
		
		return retval;
	}
	
}
